package com.zdxf.util;

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


public class RSA {
//    @Value("${rsa.publicKey}")
//    private static String defaultPublicKey;
//
//    @Value("${rsa.privateKey}")
//    private static String defaultPrivateKey;

    private static volatile KeyPair keyPair = null;

    private static String defaultPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJBPsgo8QIV++sWFsEnXjnURCVJuEkyslaMWRIj/gHQzFt//VROpdfdLGBxNOqVPmDVHZWvW9btBQkgWrV/HMjmVfYYocWdqRjORAdCXV9yePXkOjEfYBv4tpq75NKl3QABNQDNriqlf04yBVF6ftZWTbc2S5VIyS5GClXpL0APtAgMBAAECgYEAiWAEWTAAL9Sv/iYEqlaTmydrm1eC/hBwpf6FoXCwJG2aAgP7RitUS+PlgNOX11RMzbM4fg70f5xg72T/CCUEzkx8lgg7ekM91eovj/PIsIe50RFcX+uVWIGGN15V7p+SGFfBNL6VdTSg3DBH4Y9H0RwaytK/dxd+LTM4/n6oNbUCQQDsl58eihVjlMFd5j0thLwp9854WRoNaPvpFGNuytRIfzX9jDmVRs08F6S4sp6vGdNHfp5JtUlruSr0HTJmluWrAkEAnCYyY/i3hXF5IEmYWS7GfTdWizrLLaPMZQSx2mI6se6t3fdga1EcWG4KKFConYmK07E2CKboKXBFBp3+D1Z0xwJAJjzbGrR2gIGqPuLXQGQThTTnycucyk4NaL5C08U0SgNFVpUzOU0YHn4zwSYdP2+NFiEAtCj4lNB4gLu3SZ1ZwQJAaP6aFXSw2g6h1p8FzLnSB3JFRBtFcSvZjPdqK6CvPONzj3P+JksE10UumUsbBcrtSUi4P3sTUoHGOBvWMDP/EwJAMkCsjbZU9wy+EqljbJ524L5Vb1vqb0OSbchik8j+nacT3LCBX0dDFSrNJLXK6jqCQa409cJW2QOW7U037VpdXw==";
    private static String defaultPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQT7IKPECFfvrFhbBJ1451EQlSbhJMrJWjFkSI/4B0Mxbf/1UTqXX3SxgcTTqlT5g1R2Vr1vW7QUJIFq1fxzI5lX2GKHFnakYzkQHQl1fcnj15DoxH2Ab+Laau+TSpd0AATUAza4qpX9OMgVRen7WVk23NkuVSMkuRgpV6S9AD7QIDAQAB";

    private static synchronized void init() {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 可配置长度1024、512、2048
            keyPairGen.initialize(512, new SecureRandom());

            keyPair = keyPairGen.generateKeyPair();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static String getPublicKey() {
        if (keyPair == null) {
            init();
        }
        PublicKey publicKey = keyPair.getPublic();
        return Base64.encodeBase64String(publicKey.getEncoded());

    }

    public static String getPrivateKey() {
        if (keyPair == null) {
            init();
        }
        PrivateKey privateKey = keyPair.getPrivate();
        return Base64.encodeBase64String(privateKey.getEncoded());
    }

    public static String encryptByPublicKey(String source) {
        return encryptByPublicKey(source, null);
    }

    public static String decryptByPrivateKey(String source) {
        return decryptByPrivateKey(source, null);
    }

    public static String encryptByPrivateKey(String source) {
        return encryptByPrivateKey(source, null);
    }

    public static String decryptByPublicKey(String source) {
        return decryptByPublicKey(source, null);
    }

    /**
     * 公钥加密
     *
     * @param source
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey(String source, String publicKeyStr) {

        try {
            if (publicKeyStr == null || "".equals(publicKeyStr)) {
                publicKeyStr = defaultPublicKey;
            }

            byte[] decodeBase64 = Base64.decodeBase64(publicKeyStr);

            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decodeBase64);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance("RSA");

            /**
             * @ 公钥加密后的密文，每次都可以不一样，想要没测都一样，就设置固定值
             * @ cipher.init(Cipher.DECRYPT_MODE, publicKey, new
             *   SecureRandom(固定值))
             * @ cipher.init(Cipher.ENCRYPT_MODE, publicKey, new
             *   SecureRandom("1".getBytes()));
             */
            /**
             * 此种方式：相同的密钥和相同的值，每次加密后的值在变动
             */

            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            byte[] doFinal = cipher.doFinal(source.getBytes("UTF-8"));

            byte[] decodeBase64Byte = Base64.encodeBase64(doFinal);

            String decode = new String(decodeBase64Byte);

            return decode;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 私钥解密
     *
     * @param source
     * @param privateKeyStr
     * @return
     */
    public static String decryptByPrivateKey(String source, String privateKeyStr) {
        try {

            if (privateKeyStr == null || "".equals(privateKeyStr)) {
                privateKeyStr = defaultPrivateKey;
            }

            byte[] decodeBase64 = Base64.decodeBase64(privateKeyStr);

            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodeBase64);

            KeyFactory factory = KeyFactory.getInstance("RSA");

            PrivateKey privateKey = factory.generatePrivate(spec);

            Cipher cipher = Cipher.getInstance("RSA");

            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            byte[] decodeBase64Byte = Base64.decodeBase64(source.getBytes("UTF-8"));

            byte[] doFinal = cipher.doFinal(decodeBase64Byte);

            return new String(doFinal);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * =========================================================================
     * =
     * =========================================================================
     * =
     * =========================================================================
     * =
     */

    /**
     * 私钥加密
     *
     * @param source
     * @param privateKeyStr
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey(String source, String privateKeyStr) {
        try {

            if (privateKeyStr == null || "".equals(privateKeyStr)) {
                privateKeyStr = defaultPrivateKey;
            }

            byte[] decodeBase64 = Base64.decodeBase64(privateKeyStr);

            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decodeBase64);

            KeyFactory factory = KeyFactory.getInstance("RSA");

            PrivateKey privateKey = factory.generatePrivate(spec);

            Cipher cipher = Cipher.getInstance("RSA");

            // cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey, new SecureRandom());

            byte[] doFinal = cipher.doFinal(source.getBytes("UTF-8"));

            String encodeBase64String = Base64.encodeBase64String(doFinal);

            return encodeBase64String;

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥解密
     *
     * @param source
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String decryptByPublicKey(String source, String publicKeyStr) {
        try {

            if (publicKeyStr == null || "".equals(publicKeyStr)) {
                publicKeyStr = defaultPublicKey;
            }

            byte[] decodeBase64 = Base64.decodeBase64(publicKeyStr);

            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(decodeBase64);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

            Cipher cipher = Cipher.getInstance("RSA");

            // cipher.init(Cipher.DECRYPT_MODE, publicKey);
            cipher.init(Cipher.DECRYPT_MODE, publicKey, new SecureRandom());

            byte[] decodeBase64Byte = Base64.decodeBase64(source.getBytes("UTF-8"));

            byte[] doFinal = cipher.doFinal(decodeBase64Byte);

            String decode = new String(doFinal);

            return decode;

        } catch (Exception e) {

            e.printStackTrace();
        }
        return null;
    }

    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       加密数据
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String signByPrivateKey(String data, String privateKey) {
        try {

            // 解密由base64编码的私钥
            byte[] keyBytes = Base64.decodeBase64(privateKey);
            // 构造PKCS8EncodedKeySpec对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 取私钥匙对象
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
            // 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(priKey);
            signature.update(data.getBytes("UTF-8"));

            return Base64.encodeBase64String(signature.sign());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥校验数字签名
     *
     * @param data      加密数据
     * @param publicKey
     * @param sign
     * @return
     * @throws Exception
     */
    public static boolean validateSignByPublicKey(String data, String publicKey, String sign) {
        try {

            // 解密由base64编码的公钥
            byte[] keyBytes = Base64.decodeBase64(publicKey);
            // 构造X509EncodedKeySpec对象
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            // KEY_ALGORITHM 指定的加密算法
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            // 取公钥匙对象
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(data.getBytes("UTF-8"));
            // 验证签名是否正常
            return signature.verify(Base64.decodeBase64(sign));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}